package model.cubos;

import java.util.Arrays;

import model.strategys.MyStrategys;

/**
 * Esta classe reprenta o {@link CuboMagico} mais conhecido, o 3x3x3.
 * 
 * @author Joeffison Silvério de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 11/11/11 09:20
 */
public class CuboMagico3x3x3 implements CuboMagico
{

    protected Adesivo[][][] cubo;
    protected MyStrategys strategy;

    public CuboMagico3x3x3(MyStrategys strategy)
    {
	this.strategy = strategy;
	this.cubo = criaCubo3x3x3(6, 3);
    }

    protected Adesivo[][][] criaCubo3x3x3(int n_cores, int dimensao)
    {
	Adesivo[][][] cube = new Adesivo[6][3][3];
	int count = 0;
	for (int i = 0; i < n_cores; i++)
	{
	    for (int j = 0; j < dimensao; j++)
	    {
		for (int k = 0; k < dimensao; k++)
		{
		    cube[i][j][k] = new Adesivo(count++, Adesivo.getCores()[i]);

		}
	    }
	}
	/*
	 * {
	 * { Primeira cor.
	 * Cada número da matriz mais interna, representa uma peça.
	 * {0, 1, 2}, Primeira linha do cubo, para esta cor.
	 * {3, 4, 5}, Segunda linha do cubo, para esta cor.
	 * {6, 7, 8} Terceira linha do cubo, para esta cor.
	 * Olhando na vertical, vemos as colunas do cubo.
	 * },
	 * { Segunda cor.
	 * {9, 10, 11},
	 * {12, 13, 14},
	 * {15, 16, 17}
	 * },
	 * { Terceira cor.
	 * {18, 19, 20},
	 * {21, 22, 23},
	 * {24, 25, 26}
	 * },
	 * { Quarta cor.
	 * {27, 28, 29},
	 * {30, 31, 32},
	 * {33, 34, 35}
	 * },
	 * { Quinta cor.
	 * {36, 37, 38},
	 * {39, 40, 41},
	 * {42, 43, 44}
	 * },
	 * { Sexta cor.
	 * {45, 46, 47},
	 * {48, 49, 50},
	 * {51, 52, 53}
	 * }
	 * };
	 */
	return cube;
    }

    @Override
    public Adesivo[][][] getCubo()
    {
	return this.cubo;
    }

    @Override
    public void resolver()
    {
	this.strategy.resolver(this);
    }

    @Override
    public String toString()
    {
	StringBuffer espacos = new StringBuffer(); // organizar o cubo
	for (int i = 0; i < Arrays.toString(cubo[0][0]).length(); i++)
	{
	    espacos.append(" ");
	}

	StringBuffer str = new StringBuffer();
	for (int j = 0; j < cubo[0].length; j++)
	{
	    str.append(espacos);
	    str.append(Arrays.toString(cubo[4][j]));
	    str.append("\n");
	}
	int[] interacao_j = { 3, 0, 1, 2 };
	for (int i = 0; i < cubo[0].length; i++)
	{
	    for (int j : interacao_j)
	    {
		str.append(Arrays.toString(cubo[j][i]));
	    }
	    str.append("\n");
	}
	for (int j = 0; j < cubo[0].length; j++)
	{
	    str.append(espacos);
	    str.append(Arrays.toString(cubo[5][j]));
	    str.append("\n");
	}

	return str.toString();
    }

    @Override
    public void setToStringToColor()
    {
	for (int i = 0; i < 6; i++)
	{
	    for (int j = 0; j < 3; j++)
	    {
		for (Adesivo ads : this.cubo[i][j])
		{
		    ads.setToStringToColor();
		}
	    }
	}
    }

    @Override
    public void setToStringToNumbers()
    {
	for (int i = 0; i < 6; i++)
	{
	    for (int j = 0; j < 3; j++)
	    {
		for (Adesivo ads : this.cubo[i][j])
		{
		    ads.setToStringToNumbers();
		}
	    }
	}
    }

    /**
     * Pesquisa uma peca no cubo a partir da chave passada. A primeira posicao do array representa a face, o segundo
     * array representa a linha e o terceiro a coluna.
     * 
     * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com
     * @param key
     *            A chave da peca a ser procurada.
     * @return Um array de inteiros representando a posicao da peca com a chave dada.
     */
    public int[] searchPiece(int key)
    {
	for (int i = 0; i < cubo.length; i++)
	{
	    for (int j = 0; j < cubo[i].length; j++)
	    {
		for (int k = 0; k < cubo[i][j].length; k++)
		{
		    if (cubo[i][j][k].getKey() == key)
		    {
			return new int[] { i, j, k };
		    }
		}
	    }
	}
	return null;
    }

    /**
     * Metodo que calcula a posicao correta da peca passada como parametro a partir da posicao da peca central da mesma
     * cor.
     * 
     * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com
     * @param central
     *            A peca central da mesma cor.
     * @param aCalcular
     *            A peca cuja posicao sera calculada.
     * @return Um array de inteiros contendo a posicao correta da peca no cubo na forma [face, linha, coluna]
     * @throws Exception
     *             Caso o numero da face seja invalido, apenas para evitar erros de semantica.
     */
    public int[] calculaPosicaoCorreta(Adesivo central, Adesivo aCalcular) throws Exception
    {
	int indiceDeDistancia = central.getKey() - aCalcular.getKey();
	int[] retorno = this.searchPiece(central.getKey());
	retorno[2] += indiceDeDistancia;
	while (retorno[2] < -3 || retorno[2] > 3)
	{
	    if (retorno[2] < -3)
	    {
		retorno[1]++;
		retorno[2] += 3;
	    }
	    else
	    {
		retorno[1]--;
		retorno[2] -= 3;
	    }
	}
	while (retorno[1] < -3 || retorno[1] > 3)
	{
	    if (retorno[1] < -3)
	    {
		retorno[0]++;
		retorno[1] += 3;
	    }
	    else
	    {
		retorno[0]--;
		retorno[1] -= 3;
	    }
	}
	if (retorno[0] > 6 || retorno[0] < 0)
	{
	    throw new Exception("Erro de semantica!");
	}
	return retorno;

    }

    public MyStrategys getStrategy()
    {
	return strategy;
    }

}